using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.Extensions.Logging;
using Terra.Core.Common.ApiResponse;
using Terra.Core.Common.ErrorCodes.Constants;
using Terra.Core.Common.Exceptions;
using Terra.Core.Common.Models.Common;
using Terra.Core.Common.Models.Pagination;
using Terra.Core.Common.Utils;
using Terra.Data.Entities.Identity;
using Terra.Data.Models.Identity;
using Terra.Data.Repository.Identity;
using Terra.Data.UnitOfWork;
using Terra.Service.Common.Base;
using Terra.Service.Identity.Interfaces;

namespace Terra.Service.Identity.Implementations;

/// <summary>
/// 菜单服务实现
/// </summary>
public class MenuService : AppServiceBase, IMenuService
{
    private readonly IMenuRepository _menuRepository;
    private readonly ILogger<MenuService> _logger;

    private readonly IPermissionRepository _permissionRepository;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="unitOfWork">工作单元</param>
    /// <param name="menuRepository">菜单仓储</param>
    /// <param name="mapper">对象映射器</param>
    /// <param name="logger">日志记录器</param>
    /// <param name="permissionRepository">权限仓储</param>
    public MenuService(
        IUnitOfWork unitOfWork,
        IMenuRepository menuRepository,
        IMapper mapper,
        ILogger<MenuService> logger,
        IPermissionRepository permissionRepository) : base(unitOfWork, mapper)
    {
        _menuRepository = menuRepository ?? throw new ArgumentNullException(nameof(menuRepository));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _permissionRepository = permissionRepository ?? throw new ArgumentNullException(nameof(permissionRepository));
    }

    #region 查询操作

    /// <inheritdoc/>
    public async Task<ApiResponse<MenuDetailDto>> GetMenuByIdAsync(Guid id)
    {
        var menu = await _menuRepository.GetByIdAsync(id);
        if (menu == null)
        {
            _logger.LogWarning("菜单不存在: {MenuId}", id);
            return ApiResponse<MenuDetailDto>.Error(SecurityErrorCodes.MenuNotFound);
        }

        var menuDto = Mapper.Map<MenuDetailDto>(menu);
        return ApiResponse<MenuDetailDto>.Success(menuDto);
    }

    /// <inheritdoc/>
    public async Task<ApiResponse<PagedList<MenuItemDto>>> GetPagedMenusAsync(MenuQueryDto query)
    {
        var (items, totalCount) = await _menuRepository.GetPagedMenusAsync(query);

        // 映射实体到DTO
        var menuDtos = Mapper.Map<List<MenuItemDto>>(items);

        // 获取父菜单名称
        var parentIds = menuDtos
            .Where(m => m.ParentId.HasValue)
            .Select(m => m.ParentId.Value)
            .Distinct()
            .ToList();

        if (parentIds.Any())
        {
            var parentMenus = await _menuRepository.GetListAsync(m => parentIds.Contains(m.Id));
            var parentDict = parentMenus.ToDictionary(m => m.Id, m => m.Name);

            foreach (var menu in menuDtos.Where(m => m.ParentId.HasValue))
            {
                if (parentDict.TryGetValue(menu.ParentId.Value, out var parentName))
                {
                    menu.ParentName = parentName;
                }
            }
        }

        var pagedList = new PagedList<MenuItemDto>(menuDtos, totalCount, query.PageIndex, query.PageSize);
        return ApiResponse<PagedList<MenuItemDto>>.Success(pagedList);
    }

    /// <inheritdoc/>
    public async Task<ApiResponse<List<MenuTreeDto>>> GetMenuTreeAsync()
    {
        // 获取所有菜单
        var menus = await _menuRepository.GetAllMenusAsync();

        // 映射为树形DTO
        var menuDtos = Mapper.Map<List<MenuTreeDto>>(menus);

        // 构建树形结构
        var tree = TreeUtils.BuildTree<MenuTreeDto, Guid>(
            menuDtos,
            m => m.Id,
            m => m.ParentId != null ? m.ParentId.Value : default,
            m => m.Children ?? new List<MenuTreeDto>(),
            m => m.ParentId == null);

        return ApiResponse<List<MenuTreeDto>>.Success(tree);
    }

    /// <inheritdoc/>
    public async Task<ApiResponse<List<MenuSelectDto>>> GetMenuSelectListAsync()
    {
        var menus = await _menuRepository.GetAllMenusAsync();
        var menuDtos = Mapper.Map<List<MenuSelectDto>>(menus);
        return ApiResponse<List<MenuSelectDto>>.Success(menuDtos);
    }

    /// <inheritdoc/>
    public async Task<ApiResponse<List<RouterMenuDto>>> GetRouterMenuTreeAsync()
    {
        // 获取所有启用状态的菜单
        var menus = await _menuRepository.GetListAsync(m => m.Status == 1);

        // 映射为前端路由DTO
        var routerMenus = Mapper.Map<List<RouterMenuDto>>(menus);

        // 为每个路由菜单生成标识ID
        foreach (var menu in routerMenus)
        {
            if (string.IsNullOrEmpty(menu.Name))
            {
                menu.Name = Guid.NewGuid().ToString();
            }

            if (menu.Children == null)
            {
                menu.Children = new List<RouterMenuDto>();
            }
        }

        // 构建树形结构
        var menuDict = routerMenus.ToDictionary(m => m.Name);
        var rootMenus = new List<RouterMenuDto>();

        foreach (var menu in routerMenus)
        {
            var parentMenu = menus.FirstOrDefault(m => m.Id.ToString() == menu.Name)?.ParentId;
            if (parentMenu.HasValue)
            {
                var parentMenuName = menus.FirstOrDefault(m => m.Id == parentMenu.Value)?.Name;
                if (!string.IsNullOrEmpty(parentMenuName) && menuDict.TryGetValue(parentMenuName, out var parent))
                {
                    parent.Children.Add(menu);
                }
                else
                {
                    rootMenus.Add(menu);
                }
            }
            else
            {
                rootMenus.Add(menu);
            }
        }

        return ApiResponse<List<RouterMenuDto>>.Success(rootMenus);
    }

    #endregion

    #region 业务操作

    /// <inheritdoc/>
    public async Task<ApiResponse<Guid>> CreateMenuAsync(MenuCreateDto dto)
    {
        // 验证菜单名称唯一性
        if (await _menuRepository.ExistsByNameAsync(dto.Name))
        {
            return ApiResponse<Guid>.Error(SecurityErrorCodes.MenuNameAlreadyExists);
        }

        // 验证菜单路径唯一性
        if (!string.IsNullOrEmpty(dto.Path) && await _menuRepository.ExistsByPathAsync(dto.Path))
        {
            return ApiResponse<Guid>.Error(SecurityErrorCodes.MenuPathAlreadyExists);
        }

        // 验证父菜单存在
        if (dto.ParentId.HasValue)
        {
            var parentMenu = await _menuRepository.GetByIdAsync(dto.ParentId.Value);
            if (parentMenu == null)
            {
                return ApiResponse<Guid>.Error(SecurityErrorCodes.ParentMenuNotFound);
            }
        }

        // 实体映射
        var menu = Mapper.Map<Menu>(dto);

        try
        {
            // 执行创建
            menu = await _menuRepository.InsertAsync(menu);

            // 同步创建权限
            await SyncMenuPermissionsAsync(menu);
            return ApiResponse<Guid>.Success(menu.Id, "创建菜单成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "创建菜单异常: {Message}", ex.Message);
            throw;
        }
    }

    /// <inheritdoc/>
    public async Task<ApiResponse> UpdateMenuAsync(Guid id, MenuUpdateDto dto)
    {
        // 验证菜单存在
        var menu = await _menuRepository.GetByIdAsync(id);
        if (menu == null)
        {
            return ApiResponse.Error(SecurityErrorCodes.MenuNotFound);
        }

        // 验证菜单名称唯一性
        if (await _menuRepository.ExistsByNameAsync(dto.Name, id))
        {
            return ApiResponse.Error(SecurityErrorCodes.MenuNameAlreadyExists);
        }

        // 验证菜单路径唯一性
        if (!string.IsNullOrEmpty(dto.Path) && await _menuRepository.ExistsByPathAsync(dto.Path, id))
        {
            return ApiResponse.Error(SecurityErrorCodes.MenuPathAlreadyExists);
        }

        // 验证父菜单存在
        if (dto.ParentId.HasValue)
        {
            // 不能将自己设为自己的父菜单
            if (dto.ParentId.Value == id)
            {
                return ApiResponse.Error(SecurityErrorCodes.CannotSetSelfAsParent);
            }

            var parentMenu = await _menuRepository.GetByIdAsync(dto.ParentId.Value);
            if (parentMenu == null)
            {
                return ApiResponse.Error(SecurityErrorCodes.ParentMenuNotFound);
            }

            // 检查是否形成循环依赖
            var parentId = parentMenu.ParentId;
            while (parentId.HasValue)
            {
                if (parentId.Value == id)
                {
                    return ApiResponse.Error(SecurityErrorCodes.CircularDependencyFound);
                }

                var parent = await _menuRepository.GetByIdAsync(parentId.Value);
                if (parent == null)
                {
                    break;
                }

                parentId = parent.ParentId;
            }
        }

        try
        {
            // 更新菜单
            var oldName = menu.Name;
            var oldTitle = menu.Title;
            var oldStatus = menu.Status;

            // 使用AutoMapper更新实体
            Mapper.Map(dto, menu);
            await _menuRepository.UpdateAsync(menu);

            // 同步更新关联的权限
            await SyncUpdateMenuPermissionsAsync(menu, oldName, oldTitle, oldStatus);

            return ApiResponse.Success("更新菜单成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "更新菜单异常: {Message}", ex.Message);
            throw;
        }
    }

    /// <inheritdoc/>
    public async Task<ApiResponse> DeleteMenuAsync(Guid id)
    {
        // 验证菜单存在
        var menu = await _menuRepository.GetByIdAsync(id);
        if (menu == null)
        {
            return ApiResponse.Error(SecurityErrorCodes.MenuNotFound);
        }

        // 检查是否有子菜单
        var hasChildren = await _menuRepository.GetChildrenAsync(id);
        if (hasChildren.Any())
        {
            return ApiResponse.Error(SecurityErrorCodes.MenuHasChildren);
        }

        try
        {
            // 获取关联的权限
            var permissions = await _permissionRepository.GetByMenuIdAsync(id);

            // 检查权限是否被使用
            foreach (var permission in permissions)
            {
                if (await _permissionRepository.IsPermissionInUseAsync(permission.Id))
                {
                    return ApiResponse.Error(SecurityErrorCodes.PERMISSION_IN_USE,
                        $"权限[{permission.Name}]已被角色使用，无法删除");
                }
            }

            // 删除关联的权限
            await _permissionRepository.DeleteByMenuIdAsync(id);

            // 删除菜单
            await _menuRepository.DeleteByIdAsync(id);

            return ApiResponse.Success("删除菜单成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "删除菜单异常: {Message}", ex.Message);
            throw;
        }
    }

    /// <inheritdoc/>
    public async Task<ApiResponse<BatchOperationResult>> BatchDeleteMenusAsync(BatchDeleteDto<Guid> dto)
    {
        if (dto.Ids == null || !dto.Ids.Any())
        {
            return ApiResponse<BatchOperationResult>.Error(ValidationErrorCodes.CollectionCannotBeEmpty);
        }

        try
        {
            // 批量删除
            var (succeeded, failedIds) = await _menuRepository.DeleteMenusAsync(dto.Ids);

            // 构建结果
            var result = BatchOperationResult.Create(
                dto.Ids.Count - failedIds.Count,
                failedIds.Count,
                failedIds
            );

            if (succeeded)
            {
                _logger.LogInformation("批量删除菜单成功: {SuccessCount}个", result.SuccessCount);
                return ApiResponse<BatchOperationResult>.Success(result, "批量删除菜单成功");
            }
            else
            {
                _logger.LogWarning("批量删除菜单部分成功: 成功{SuccessCount}个, 失败{FailedCount}个",
                    result.SuccessCount, result.FailedCount);
                return ApiResponse<BatchOperationResult>.Error(
                    DataErrorCodes.BatchPartialFailure,
                    result.SuccessCount,
                    result.FailedCount
                );
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "批量删除菜单异常: {Message}", ex.Message);
            throw;
        }
    }

    /// <summary>
    /// 同步创建菜单权限
    /// </summary>
    public async Task<ApiResponse> SyncMenuPermissionsAsync(Menu menu)
    {
        try
        {
            var permissions = new List<Permission>();

            // 1. 创建菜单访问权限
            if (menu.Type != "button") // 按钮不需要创建访问权限
            {
                permissions.Add(new Permission
                {
                    Name = Permission.GenerateName(menu),
                    Code = Permission.GenerateCode(menu),
                    Type = "menu",
                    MenuId = menu.Id,
                    Description = $"访问{menu.Title}的权限",
                    Status = menu.Status,
                    IsSystem = true
                });
            }

            // 2. 如果是按钮，创建操作权限
            if (menu.Type == "button")
            {
                // 获取父菜单
                var parentMenu = await _menuRepository.GetByIdAsync(menu.ParentId.Value);
                if (parentMenu != null)
                {
                    permissions.Add(new Permission
                    {
                        Name = Permission.GenerateName(parentMenu, menu.Title),
                        Code = Permission.GenerateCode(parentMenu, menu.Name),
                        Type = "operation",
                        MenuId = parentMenu.Id, // 关联到父菜单
                        Description = $"{parentMenu.Title}的{menu.Title}操作权限",
                        Status = menu.Status,
                        IsSystem = true
                    });
                }
            }

            // 批量创建权限
            if (permissions.Any())
            {
                await _permissionRepository.CreatePermissionsAsync(permissions);
            }

            return ApiResponse.Success("同步菜单权限成功");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "同步菜单权限异常: {Message}", ex.Message);
            throw;
        }
    }

    /// <summary>
    /// 同步更新菜单权限
    /// </summary>
    private async Task SyncUpdateMenuPermissionsAsync(Menu menu, string oldName, string oldTitle, int oldStatus)
    {
        var permissions = await _permissionRepository.GetByMenuIdAsync(menu.Id);
        var updatedPermissions = new List<Permission>();

        foreach (var permission in permissions)
        {
            var needUpdate = false;

            // 1. 同步状态
            if (permission.Status != menu.Status)
            {
                permission.Status = menu.Status;
                needUpdate = true;
            }

            // 2. 同步名称
            if (oldTitle != menu.Title)
            {
                permission.Name = permission.Type == "menu"
                    ? Permission.GenerateName(menu)
                    : Permission.GenerateName(menu, permission.Name.Replace(oldTitle, ""));
                needUpdate = true;
            }

            // 3. 同步编码
            if (oldName != menu.Name)
            {
                permission.Code = permission.Type == "menu"
                    ? Permission.GenerateCode(menu)
                    : Permission.GenerateCode(menu, permission.Code.Split(':').Last());
                needUpdate = true;
            }

            if (needUpdate)
            {
                updatedPermissions.Add(permission);
            }
        }

        if (updatedPermissions.Any())
        {
            await _permissionRepository.UpdatePermissionsAsync(updatedPermissions);
        }
    }
    #endregion
}